unit Affixes;

interface

uses
// Delphi units
  SysUtils, Classes, IniFiles,
// own units
  uVars, UConfig;

type
  {TODO: Add page for editing Affixes in HODBE}
  {DONE: Kill AdvItem, replace its job to AffixConfig}

  NAffixParam = (apID, apType, apName0, apName1, apName2, apName3, apBonus0,
    apBonus1, apGroup, apLevel, apPrice);
  NAffixType = (atSuffix, atPrefix);

  TAffixConfig = class(TConfig)
  private
    function GetIntValue(Index: Integer; Param: NAffixParam): Integer;
    procedure SetIntValue(Index: Integer; Param: NAffixParam;
      const Value: Integer);
  protected
    function GetItem(Index: Integer; Param: NAffixParam): string;
    procedure SetItem(Index: Integer; Param: NAffixParam; const Value: string);
    function GetWItem(Index, Param: Integer): string; override;
    procedure SetWItem(Index, Param: Integer; const Value: string); override;
    function GetParamCnt: Integer; override;
    function GetParamName(Param: Integer): string; override;
    function BuidAffixParam(Param: string; Idx: Integer): NAffixParam;
  public
    property Items[Index: Integer; Param: NAffixParam]: string read GetItem write
      SetItem;
    property IntValues[Index: Integer; Param: NAffixParam]: Integer read GetIntValue write
      SetIntValue;
    function IDString(Index: Integer; Param: NAffixParam): string;
    function GenAffix(AType: NAffixType; Level: Integer = -1;
      Group: Integer = -1): Integer;
    function AffixCountByType(AType: NAffixType): Integer;
    function Bonus(AffIdx, BonusIdx: Integer; var Target: string; var Value: Integer): Boolean;
    function Name(AffIdx: Integer; Gender: Integer): string;
  end;

const
  DefaultTextSection = 'Default';
  Delim = '|';
  AffixParamColWidths: array[NAffixParam] of Integer =
    (20, 60, 90, 90, 90, 90, 90, 90, 20, 20, 20);
  AffixParamColCount = Ord(High(NAffixParam)) + 1;
  AffixParamType: array[NAffixParam] of NParamType = (npInteger, npList, npString,
    npString, npString, npString, npString, npString, npInteger, npInteger, npInteger);


function AffixConfig(): TAffixConfig;
function BonusCount: Integer;

var
  AffixParamNames: array[NAffixParam] of string;

implementation

uses
// Delphi units
  TypInfo,
// Own units
  uBox, uStrUtils, uUtils;

var
  TheAffixConfig: TAffixConfig;
  AffixParamEnumPtr: Pointer;

function AffixConfig(): TAffixConfig;
begin
  Result := TheAffixConfig;
end;

function BonusCount: Integer;
var
  ap: NAffixParam;
begin
  Result := 0;
  for ap := Low(NAffixParam) to High(NAffixParam) do
    Inc(Result, Ord(Pos('Bonus', EnumText(AffixParamEnumPtr, Ord(ap), 0)) > 0));
end;

{ TAffixConfig }

function TAffixConfig.AffixCountByType(AType: NAffixType): Integer;
var
  i: Integer;
begin
  Result := 0;
  for i := 0 to Count - 1 do
    Inc(Result, Ord(Items[i, apType] = EnumText(AffixParamEnumPtr, Ord(AType), 0)));
end;

function TAffixConfig.Bonus(AffIdx, BonusIdx: Integer; var Target: string;
  var Value: Integer): Boolean;
var
  SR: TSplitResult;
  ABonus: string;
begin
  Target := '';
  Value := 0;
  ABonus := Items[AffIdx, BuidAffixParam('apBonus', BonusIdx)];
  Result := ABonus <> '';
  if not Result then
    Exit;
  SR := Explode(',', ABonus);
  Target := SR[0];
  Value := StrToInt(SR[1]);
end;

function TAffixConfig.BuidAffixParam(Param: string; Idx: Integer): NAffixParam;
begin
  Result := NAffixParam(GetEnumValue(AffixParamEnumPtr, Param + IntToStr(Idx)));
end;

function TAffixConfig.GenAffix(AType: NAffixType; Level: Integer = -1;
  Group: Integer = -1): Integer;
var
  i, Cnt: Integer;
  ptr: Pointer;
  arr: array[0..511] of Integer;
begin
  Result := 0;
  Cnt := 0;
  ptr := TypeInfo(NAffixType);
  for i := 0 to Count - 1 do
    if (Items[i, apType] = EnumText(ptr, Ord(AType), 0)) and
      ((Level = -1) or (IntValues[i, apLevel] = Level)) and
      ((Group = -1) or (IntValues[i, apGroup] = Group))
    then
      arr[PostInc(Cnt)] := IntValues[i, apID];
  if Cnt = 0 then
    Result := 0
  else  
    Result := arr[Random(Cnt)];
end;

function TAffixConfig.GetIntValue(Index: Integer; Param: NAffixParam): Integer;
begin
  Result := StrToIntDef(Items[Index, Param], 0);
end;

function TAffixConfig.GetItem(Index: Integer; Param: NAffixParam): string;
begin
  if Param = apID then
    Result := IntToStr(Index)
  else
    Result := FWrapper.ReadString(IDString(Index, Param));
end;

function TAffixConfig.GetParamCnt: Integer;
begin
  Result := AffixParamColCount;
end;

function TAffixConfig.GetParamName(Param: Integer): string;
begin
  Result := AffixParamNames[NAffixParam(Param)];
end;

function TAffixConfig.GetWItem(Index, Param: Integer): string;
begin
  Result := Items[Index, NAffixParam(Param)];
end;

function TAffixConfig.IDString(Index: Integer; Param: NAffixParam): string;
begin
  Result := Format('%d%s%s', [Index, FWrapper.Delim, AffixParamNames[Param]]);
end;

function TAffixConfig.Name(AffIdx, Gender: Integer): string;
begin
  Result := Items[AffIdx, BuidAffixParam('apName', Gender)];
end;

procedure TAffixConfig.SetIntValue(Index: Integer; Param: NAffixParam;
  const Value: Integer);
begin
  Items[Index, Param] := IntToStr(Value);
end;

procedure TAffixConfig.SetItem(Index: Integer; Param: NAffixParam;
  const Value: string);
begin
  if Param <> apID then
    FWrapper.WriteString(IDString(Index, Param), Value);
end;

procedure TAffixConfig.SetWItem(Index, Param: Integer; const Value: string);
begin
  Items[Index, NAffixParam(Param)] := Value;
end;

var
  I: NAffixParam;

initialization
  AffixParamEnumPtr := TypeInfo(NAffixType);
  TheAffixConfig := TAffixConfig.Create(TIniWrapper);
  TheAffixConfig.LoadFromFile(Path + 'data\Affixes.ini');
  for i := Low(NAffixParam) to High(NAffixParam) do
    AffixParamNames[i] := EnumText(TypeInfo(NAffixParam), Ord(i));

finalization
  FreeAndNil(TheAffixConfig);
end.
